home *** CD-ROM | disk | FTP | other *** search
/ Programming an RTS Game with Direct3D / Programming an RTS Game with Direct3D.iso / Examples / Chapter 7 / Example 7.4 / skinnedMesh.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2006-07-27  |  9.0 KB  |  311 lines

  1. #include "skinnedMesh.h"
  2.  
  3. class BONE_HIERARCHY: public ID3DXAllocateHierarchy
  4. {
  5.     public:
  6.         STDMETHOD(CreateFrame)(THIS_ LPCSTR Name, LPD3DXFRAME *ppNewFrame);
  7.         STDMETHOD(CreateMeshContainer)(THIS_ LPCTSTR Name, CONST D3DXMESHDATA * pMeshData, CONST D3DXMATERIAL * pMaterials, CONST D3DXEFFECTINSTANCE * pEffectInstances, DWORD NumMaterials, CONST DWORD * pAdjacency, LPD3DXSKININFO pSkinInfo, LPD3DXMESHCONTAINER * ppNewMeshContainer);
  8.         STDMETHOD(DestroyFrame)(THIS_ LPD3DXFRAME pFrameToFree);
  9.         STDMETHOD(DestroyMeshContainer)(THIS_ LPD3DXMESHCONTAINER pMeshContainerBase);
  10. };
  11.  
  12. HRESULT BONE_HIERARCHY::CreateFrame(LPCSTR Name, LPD3DXFRAME *ppNewFrame)
  13. {
  14.     BONE *newBone = new BONE;
  15.     memset(newBone, 0, sizeof(BONE));
  16.  
  17.     //Copy name
  18.     if(Name != NULL)
  19.     {
  20.         newBone->Name = new char[strlen(Name)+1];
  21.         strcpy(newBone->Name, Name);
  22.     }
  23.  
  24.     //Set the transformation matrices
  25.     D3DXMatrixIdentity(&newBone->TransformationMatrix);
  26.     D3DXMatrixIdentity(&newBone->CombinedTransformationMatrix);
  27.  
  28.     //Return the new bone...
  29.     *ppNewFrame = (D3DXFRAME*)newBone;
  30.  
  31.     return S_OK;
  32. }
  33.  
  34. HRESULT BONE_HIERARCHY::CreateMeshContainer(LPCSTR Name,
  35.                                             CONST D3DXMESHDATA *pMeshData,
  36.                                             CONST D3DXMATERIAL *pMaterials,
  37.                                             CONST D3DXEFFECTINSTANCE *pEffectInstances,
  38.                                             DWORD NumMaterials,
  39.                                             CONST DWORD *pAdjacency,
  40.                                             LPD3DXSKININFO pSkinInfo,
  41.                                             LPD3DXMESHCONTAINER *ppNewMeshContainer)
  42. {
  43.     //Create new Bone Mesh
  44.     BONEMESH *boneMesh = new BONEMESH;
  45.     memset(boneMesh, 0, sizeof(BONEMESH));
  46.  
  47.     //Get mesh data
  48.     boneMesh->OriginalMesh = pMeshData->pMesh;
  49.     boneMesh->MeshData.pMesh = pMeshData->pMesh;
  50.     boneMesh->MeshData.Type = pMeshData->Type;
  51.     pMeshData->pMesh->AddRef();        //Add Reference so that the mesh isnt deallocated
  52.     IDirect3DDevice9 *m_pDevice = NULL;    
  53.     pMeshData->pMesh->GetDevice(&m_pDevice);    //Get m_pDevice ptr from mesh
  54.  
  55.     //Copy materials and load textures (just like with a static mesh)
  56.     for(int i=0;i<NumMaterials;i++)
  57.     {
  58.         D3DXMATERIAL mtrl;
  59.         memcpy(&mtrl, &pMaterials[i], sizeof(D3DXMATERIAL));
  60.         boneMesh->materials.push_back(mtrl.MatD3D);
  61.  
  62.         char textureFname[200];
  63.         strcpy(textureFname, "mesh/");
  64.         strcat(textureFname, mtrl.pTextureFilename);
  65.  
  66.         //Load texture
  67.         IDirect3DTexture9* newTexture = NULL;
  68.         D3DXCreateTextureFromFile(m_pDevice, textureFname, &newTexture);
  69.         boneMesh->textures.push_back(newTexture);
  70.     }
  71.  
  72.     if(pSkinInfo != NULL)
  73.     {
  74.         //Get Skin Info
  75.         boneMesh->pSkinInfo = pSkinInfo;
  76.         pSkinInfo->AddRef();    //Add reference so that the SkinInfo isnt deallocated
  77.  
  78.         //Clone mesh and store in boneMesh->MeshData.pMesh
  79.         pMeshData->pMesh->CloneMeshFVF(D3DXMESH_MANAGED, pMeshData->pMesh->GetFVF(), 
  80.                                        m_pDevice, &boneMesh->MeshData.pMesh);
  81.         
  82.         //Get Attribute Table
  83.         boneMesh->MeshData.pMesh->GetAttributeTable(NULL, &boneMesh->NumAttributeGroups);
  84.         boneMesh->attributeTable = new D3DXATTRIBUTERANGE[boneMesh->NumAttributeGroups];
  85.         boneMesh->MeshData.pMesh->GetAttributeTable(boneMesh->attributeTable, NULL);
  86.  
  87.         //Create bone offset and current matrices
  88.         int NumBones = pSkinInfo->GetNumBones();
  89.         boneMesh->boneOffsetMatrices = new D3DXMATRIX[NumBones];        
  90.         boneMesh->currentBoneMatrices = new D3DXMATRIX[NumBones];
  91.  
  92.         //Get bone offset matrices
  93.         for(int i=0;i < NumBones;i++)
  94.             boneMesh->boneOffsetMatrices[i] = *(boneMesh->pSkinInfo->GetBoneOffsetMatrix(i));
  95.     }
  96.  
  97.     //Set ppNewMeshContainer to the newly created boneMesh container
  98.     *ppNewMeshContainer = boneMesh;
  99.  
  100.     return S_OK;
  101. }
  102.  
  103. HRESULT BONE_HIERARCHY::DestroyFrame(LPD3DXFRAME pFrameToFree) 
  104. {
  105.     if(pFrameToFree)
  106.     {
  107.         //Free name
  108.         if(pFrameToFree->Name != NULL)
  109.             delete [] pFrameToFree->Name;
  110.  
  111.         //Free bone
  112.         delete pFrameToFree;
  113.     }
  114.     pFrameToFree = NULL;
  115.  
  116.     return S_OK; 
  117. }
  118.  
  119. HRESULT BONE_HIERARCHY::DestroyMeshContainer(LPD3DXMESHCONTAINER pMeshContainerBase)
  120. {
  121.     BONEMESH *boneMesh = (BONEMESH*)pMeshContainerBase;
  122.  
  123.     //Release textures
  124.     for(int i=0;i < boneMesh->textures.size();i++)
  125.         if(boneMesh->textures[i] != NULL)
  126.             boneMesh->textures[i]->Release();
  127.  
  128.     //Release mesh data
  129.     if(boneMesh->MeshData.pMesh)boneMesh->MeshData.pMesh->Release();
  130.     if(boneMesh->pSkinInfo)boneMesh->pSkinInfo->Release();
  131.     if(boneMesh->OriginalMesh)boneMesh->OriginalMesh->Release();
  132.     delete boneMesh;
  133.  
  134.     return S_OK;
  135. }
  136.  
  137.  
  138. //////////////////////////////////////////////////////////////////////////////////////////////////
  139. //                                    SKINNED MESH                                                //
  140. //////////////////////////////////////////////////////////////////////////////////////////////////
  141.  
  142. struct VERTEX{
  143.     VERTEX();
  144.     VERTEX(D3DXVECTOR3 pos, D3DCOLOR col){position = pos; color = col;}
  145.     D3DXVECTOR3 position;
  146.     D3DCOLOR color;
  147.     static const DWORD FVF;
  148. };
  149.  
  150. const DWORD VERTEX::FVF = D3DFVF_XYZ | D3DFVF_DIFFUSE;
  151.  
  152. SKINNEDMESH::SKINNEDMESH()
  153. {
  154.     m_pRootBone = NULL;
  155.     m_pAnimControl = NULL;
  156. }
  157.  
  158. SKINNEDMESH::~SKINNEDMESH()
  159. {
  160.     BONE_HIERARCHY boneHierarchy;
  161.     boneHierarchy.DestroyFrame(m_pRootBone);
  162.     if(m_pAnimControl)m_pAnimControl->Release();
  163. }
  164.  
  165. void SKINNEDMESH::Load(char fileName[], IDirect3DDevice9 *Dev)
  166. {
  167.     m_pDevice = Dev;
  168.     BONE_HIERARCHY boneHierarchy;
  169.  
  170.     D3DXLoadMeshHierarchyFromX(fileName, D3DXMESH_MANAGED, 
  171.                                m_pDevice, &boneHierarchy,
  172.                                NULL, &m_pRootBone, &m_pAnimControl);
  173.  
  174.     SetupBoneMatrixPointers((BONE*)m_pRootBone);
  175.  
  176.     //Update all the bones
  177.     D3DXMATRIX i;
  178.     D3DXMatrixIdentity(&i);
  179.     UpdateMatrices((BONE*)m_pRootBone, &i);
  180. }
  181.  
  182. void SKINNEDMESH::UpdateMatrices(BONE* bone, D3DXMATRIX *parentMatrix)
  183. {
  184.     if(bone == NULL)return;
  185.  
  186.     D3DXMatrixMultiply(&bone->CombinedTransformationMatrix,
  187.                        &bone->TransformationMatrix,
  188.                        parentMatrix);
  189.  
  190.     if(bone->pFrameSibling)UpdateMatrices((BONE*)bone->pFrameSibling, parentMatrix);
  191.     if(bone->pFrameFirstChild)UpdateMatrices((BONE*)bone->pFrameFirstChild, &bone->CombinedTransformationMatrix);
  192. }
  193.  
  194. void SKINNEDMESH::Render(BONE *bone)
  195. {
  196.     if(bone == NULL)bone = (BONE*)m_pRootBone;
  197.  
  198.     //If there is a mesh to render...
  199.     if(bone->pMeshContainer != NULL)
  200.     {
  201.         BONEMESH *boneMesh = (BONEMESH*)bone->pMeshContainer;
  202.  
  203.         if (boneMesh->pSkinInfo != NULL)
  204.         {        
  205.             // set up bone transforms
  206.             int numBones = boneMesh->pSkinInfo->GetNumBones();
  207.             for(int i=0;i < numBones;i++)
  208.                 D3DXMatrixMultiply(&boneMesh->currentBoneMatrices[i],
  209.                                    &boneMesh->boneOffsetMatrices[i], 
  210.                                    boneMesh->boneMatrixPtrs[i]);
  211.  
  212.             //Update the skinned mesh
  213.             BYTE *src = NULL, *dest = NULL;
  214.             boneMesh->OriginalMesh->LockVertexBuffer(D3DLOCK_READONLY, (VOID**)&src);
  215.             boneMesh->MeshData.pMesh->LockVertexBuffer(0, (VOID**)&dest);
  216.  
  217.             boneMesh->pSkinInfo->UpdateSkinnedMesh(boneMesh->currentBoneMatrices, NULL, src, dest);
  218.  
  219.             boneMesh->MeshData.pMesh->UnlockVertexBuffer();
  220.             boneMesh->OriginalMesh->UnlockVertexBuffer();
  221.  
  222.             //Render the mesh
  223.             for(int i=0;i < boneMesh->NumAttributeGroups;i++)
  224.             {
  225.                 int mtrlIndex = boneMesh->attributeTable[i].AttribId;
  226.                 m_pDevice->SetMaterial(&(boneMesh->materials[mtrlIndex]));
  227.                 m_pDevice->SetTexture(0, boneMesh->textures[mtrlIndex]);
  228.                 boneMesh->MeshData.pMesh->DrawSubset(mtrlIndex);
  229.             }
  230.         }
  231.     }
  232.  
  233.     if(bone->pFrameSibling != NULL)Render((BONE*)bone->pFrameSibling);
  234.     if(bone->pFrameFirstChild != NULL)Render((BONE*)bone->pFrameFirstChild);
  235. }
  236.  
  237. void SKINNEDMESH::SetupBoneMatrixPointers(BONE *bone)
  238. {
  239.     if(bone->pMeshContainer != NULL)
  240.     {
  241.         BONEMESH *boneMesh = (BONEMESH*)bone->pMeshContainer;
  242.  
  243.         if(boneMesh->pSkinInfo != NULL)
  244.         {
  245.             int NumBones = boneMesh->pSkinInfo->GetNumBones();
  246.             boneMesh->boneMatrixPtrs = new D3DXMATRIX*[NumBones];
  247.  
  248.             for(int i=0;i < NumBones;i++)
  249.             {
  250.                 BONE *b = (BONE*)D3DXFrameFind(m_pRootBone, boneMesh->pSkinInfo->GetBoneName(i));
  251.                 if(b != NULL)boneMesh->boneMatrixPtrs[i] = &b->CombinedTransformationMatrix;
  252.                 else boneMesh->boneMatrixPtrs[i] = NULL;
  253.             }
  254.         }
  255.     }
  256.  
  257.     if(bone->pFrameSibling != NULL)SetupBoneMatrixPointers((BONE*)bone->pFrameSibling);
  258.     if(bone->pFrameFirstChild != NULL)SetupBoneMatrixPointers((BONE*)bone->pFrameFirstChild);
  259. }
  260.  
  261. BONE* SKINNEDMESH::FindBone(char name[])
  262. {
  263.     return (BONE*) D3DXFrameFind(m_pRootBone, name);
  264. }
  265.  
  266. void SKINNEDMESH::SetPose(D3DXMATRIX world, ID3DXAnimationController* animControl, float time)
  267. {
  268.     if(animControl != NULL)
  269.         animControl->AdvanceTime(time, NULL);
  270.     else m_pAnimControl->AdvanceTime(time, NULL);
  271.  
  272.     UpdateMatrices((BONE*)m_pRootBone, &world);
  273. }
  274.  
  275. void SKINNEDMESH::SetAnimation(char name[])
  276. {
  277.     ID3DXAnimationSet *anim = NULL;
  278.  
  279.     for(int i=0;i<m_pAnimControl->GetMaxNumAnimationSets();i++)
  280.     {
  281.         anim = NULL;
  282.         m_pAnimControl->GetAnimationSet(i, &anim);
  283.  
  284.         if(anim != NULL)
  285.         {
  286.             if(strcmp(name, anim->GetName()) == 0)
  287.                 m_pAnimControl->SetTrackAnimationSet(0, anim);
  288.             anim->Release();
  289.         }
  290.     }
  291. }
  292.  
  293. std::vector<std::string> SKINNEDMESH::GetAnimations()
  294. {
  295.     ID3DXAnimationSet *anim = NULL;
  296.     std::vector<std::string> animations;
  297.  
  298.     for(int i=0;i<m_pAnimControl->GetMaxNumAnimationSets();i++)
  299.     {
  300.         anim = NULL;
  301.         m_pAnimControl->GetAnimationSet(i, &anim);
  302.  
  303.         if(anim != NULL)
  304.         {
  305.             animations.push_back(anim->GetName());
  306.             anim->Release();
  307.         }
  308.     }
  309.  
  310.     return animations;
  311. }